package db;

import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.HashMap;



/**
 * DB에 실제로 query를 실행하는 클래스.
 * @author (주)열음소프트
 * @version 1.0
 */
public class DAO {

	/**
	 * Select 쿼리를 실행하는 메소드
	 * @param queryStr 쿼리 문장
	 * @param param preparedStatment문장에 들어갈 파라메터 배열
	 * @return Select한 결과를 담은 ArrayList
	 *
	 */
	public static ArrayList select(Connection con,String queryStr, String[] param) throws Exception{
		ArrayList list = null;

		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{

			pstmt = con.prepareStatement(queryStr);
			for (int i=0;param!=null && i<param.length;i++){
				pstmt.setString(i+1,param[i]);
			}
			rs = pstmt.executeQuery();

			list = getList(rs);
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}finally{
			try{
				if (rs!=null) rs.close();
			}catch(Exception ex){ex.printStackTrace();}
			try{
				if (pstmt!=null) pstmt.close();
			}catch(Exception ex){ex.printStackTrace();}

		}
		return list;
	}

	public static ArrayList select(Connection con,String queryStr) throws Exception{
		ArrayList list = null;

		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{

			pstmt = con.prepareStatement(queryStr);
			rs = pstmt.executeQuery();

			list = getList(rs);
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}finally{
			try{
				if (rs!=null) rs.close();
			}catch(Exception ex){ex.printStackTrace();}
			try{
				if (pstmt!=null) pstmt.close();
			}catch(Exception ex){ex.printStackTrace();}

		}
		return list;
	}
	/**
	 * Update 쿼리를 실행하는 메소드
	 * @param queryStr 쿼리 문장
	 * @param param preparedStatment문장에 들어갈 파라메터 배열
	 * @return Update한 결과를 담은 int
	 *
	 */
	public static int update(Connection con,String queryStr, String[] param) throws Exception{
		PreparedStatement pstmt = null;

		int resultCnt=0;
		try{
			pstmt = con.prepareStatement(queryStr);
			for (int j=0;param!=null && j<param.length;j++){
				System.out.println(param[j]);
				pstmt.setString(j+1,param[j]);
			}
			resultCnt=pstmt.executeUpdate();

		}catch(Exception e){
			resultCnt=-1;
			e.printStackTrace();
			throw e;
		}finally{

			try{
				if (pstmt!=null) pstmt.close();
			}catch(Exception ex){ex.printStackTrace();}

		}
		return resultCnt;
	}

	/**
	 * 프로시져 쿼리를 실행하는 메소드
	 * @param queryStr 쿼리 문장
	 * @param param CallableStatment문장에 들어갈 파라메터 배열
	 * @return Update한 결과를 담은 int
	 *
	 */
	public static void callProcedure(Connection con,String queryStr, String[] param) throws Exception{
		CallableStatement cstmt = null;

		try{
			cstmt = con.prepareCall(queryStr);
			for (int j=0 ; param!=null && j < param.length ; j++){
				System.out.println(param[j]);
				cstmt.setString(j+1,param[j]);
			}
			cstmt.execute();

		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}finally{

			try{
				if (cstmt!=null) cstmt.close();
			}catch(Exception ex){ex.printStackTrace();}

		}

	}

	/**
	 * CLOB컬럼을 포함한 Update 쿼리를 실행하는 메소드
	 * @param queryStr 최초 (insert or update) 쿼리 문장
	 * @param clobQuery CLOB 칼럼을 셀렉트해오는 쿼리문장
	 * @param param 최초 (insert or update) preparedStatment문장에 들어갈 파라메터 배열
	 * @param clobParam CLOB 칼럼을 셀렉트해오는 쿼리문장에들어갈 파라메터 배열
	 * @param clobData  CLOB 칼럼에 들어갈 데이터를 담은 배열
	 * @return Update한 결과를 담은 int
	 *
	 */


	/**
	 * 멀티row Update 쿼리를 실행하는 메소드
	 * @param queryStr 쿼리 문장
	 * @param paramList preparedStatment문장에 들어갈 파라메터 배열을 담은 리스트
	 * @return Update한 결과를 담은 int
	 *
	 */
	public static int updateMulti(Connection con,String queryStr, ArrayList paramList) throws Exception{
		PreparedStatement pstmt = null;

		int resultCnt=0;
		try{
			pstmt = con.prepareStatement(queryStr);
			if (paramList!=null && paramList.size()>0){
				for (int i=0; i<paramList.size();i++){
					String[] param =(String[])paramList.get(i);
					for (int j=0;param!=null && j<param.length;j++){
						System.out.println(param[j]);
						pstmt.setString(j+1,param[j]);
					}
					resultCnt=pstmt.executeUpdate();
				}
			}else{
				resultCnt=pstmt.executeUpdate();
			}

		}catch(Exception e){
			resultCnt=-1;
			e.printStackTrace();
			throw e;
		}finally{

			try{
				if (pstmt!=null) pstmt.close();
			}catch(Exception ex){ex.printStackTrace();}

		}
		return resultCnt;
	}




	/**
	 * Resultset을 ArrayList에 담아주는 메소드
	 * @param rs ResultSet
	 * @return 결과를 담은 List
	 *
	 */
	public static ArrayList getList(ResultSet rs) throws Exception {

		ArrayList array = new ArrayList();

		try {
			ResultSetMetaData rsmd = rs.getMetaData();

			HashMap vo = null;
			String imsi = null;
			while(rs.next())
			{
				vo = new HashMap();
				for( int j =1; j<=rsmd.getColumnCount(); j++)
				{
					imsi = null;
					if ("CLOB".equals(rsmd.getColumnTypeName(j))){
						if (rs.getCharacterStream(j) == null) {
							imsi = "";
						} else {
							BufferedReader breader = new BufferedReader(rs.getCharacterStream(j));
							StringBuffer clobBuffer = new StringBuffer();
							char[] buffer = new char[10*1024];
							int read = 0 ;
							if (breader != null){
								try{
									while ((read = breader.read(buffer,0,10*1024)) != -1){
										clobBuffer.append(buffer,0,read);
									}
								}catch(Exception e){
									 throw e;
								}finally{
									breader.close();
								}
								imsi = clobBuffer.toString();
							}
						}

					}else {
						imsi = rs.getString(j) ;
					}
					vo.put(rsmd.getColumnName(j) , imsi );

				}
				array.add(vo);

			}

		} catch (Exception e) {
			throw e;
		}

		return array;

	}
}
